#include "AD7997Driver.h"
#include "driver/i2c.h"
#include "esp_log.h"

#define I2C_MASTER_PORT_NUM        I2C_NUM_0
#define I2C_MASTER_TIMEOUT_MS       1000

// 寄存器地址
#define AD799X_CONV_RES_REG         0x00
#define AD799X_ALERT_STATUS_REG     0x01
#define AD799X_CONFIG_REG           0x02
#define AD799X_CYCLE_TIMER_REG      0x03
// 其他寄存器地址...

// 配置寄存器位定义
#define CH1_BIT                     (1 << 4)
#define CH2_BIT                     (1 << 5)
#define CH3_BIT                     (1 << 6)
#define CH4_BIT                     (1 << 7)
#define CH5_BIT                     (1 << 8)
#define CH6_BIT                     (1 << 9)
#define CH7_BIT                     (1 << 10)
#define CH8_BIT                     (1 << 11)
#define FLTR_BIT                    (1 << 3)
#define ALERT_EN_BIT                (1 << 2)
#define BUSY_ALERT_BIT              (1 << 1)
#define ALERT_POLARITY_BIT          (1 << 0)

#define TAG "AD7998Driver"

// 写入单个字节到指定寄存器
static esp_err_t ad799x_write_byte(uint8_t dev_addr, uint8_t reg_addr, uint8_t data) {
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (dev_addr << 1) | I2C_MASTER_WRITE, true);
    i2c_master_write_byte(cmd, reg_addr, true);
    i2c_master_write_byte(cmd, data, true);
    i2c_master_stop(cmd);
    esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_PORT_NUM, cmd, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
    i2c_cmd_link_delete(cmd);
    return ret;
}

// 从指定寄存器读取单个字节
static esp_err_t ad799x_read_byte(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data) {
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (dev_addr << 1) | I2C_MASTER_WRITE, true);
    i2c_master_write_byte(cmd, reg_addr, true);
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (dev_addr << 1) | I2C_MASTER_READ, true);
    i2c_master_read_byte(cmd, data, I2C_MASTER_NACK);
    i2c_master_stop(cmd);
    esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_PORT_NUM, cmd, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
    i2c_cmd_link_delete(cmd);
    return ret;
}

// 写入两个字节到指定寄存器
static esp_err_t ad799x_write_two_bytes(uint8_t dev_addr, uint8_t reg_addr, uint16_t data) {
    uint8_t msb = (data >> 8) & 0xFF;
    uint8_t lsb = data & 0xFF;
    
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (dev_addr << 1) | I2C_MASTER_WRITE, true);
    i2c_master_write_byte(cmd, reg_addr, true);
    i2c_master_write_byte(cmd, msb, true);
    i2c_master_write_byte(cmd, lsb, true);
    i2c_master_stop(cmd);
    esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_PORT_NUM, cmd, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
    i2c_cmd_link_delete(cmd);
    return ret;
}

// 从指定寄存器读取两个字节
static esp_err_t ad799x_read_two_bytes(uint8_t dev_addr, uint8_t reg_addr, uint16_t *data) {
    uint8_t msb, lsb;
    
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (dev_addr << 1) | I2C_MASTER_WRITE, true);
    i2c_master_write_byte(cmd, reg_addr, true);
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (dev_addr << 1) | I2C_MASTER_READ, true);
    i2c_master_read_byte(cmd, &msb, I2C_MASTER_ACK);
    i2c_master_read_byte(cmd, &lsb, I2C_MASTER_NACK);
    i2c_master_stop(cmd);
    esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_PORT_NUM, cmd, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
    i2c_cmd_link_delete(cmd);
    
    if (ret == ESP_OK) {
        *data = (msb << 8) | lsb;
    }
    return ret;
}

// 初始化AD799X设备
esp_err_t ad799x_init(uint8_t dev_addr) {
    // 重置配置寄存器为默认值
    uint16_t config = 0x0000;
    esp_err_t ret = ad799x_write_two_bytes(dev_addr, AD799X_CONFIG_REG, config);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to initialize configuration register,err code is:%d", (int)ret);
        return ret;
    }
    
    // 设置默认通道 (CH1)
    ret = ad799x_set_channel(dev_addr, CH1_BIT);
    return ret;
}

// 设置要转换的通道
esp_err_t ad799x_set_channel(uint8_t dev_addr, uint16_t channel_mask) {
    // 读取当前配置
    uint16_t config;
    esp_err_t ret = ad799x_read_two_bytes(dev_addr, AD799X_CONFIG_REG, &config);
    if (ret != ESP_OK) {
        return ret;
    }
    
    // 清除通道位并设置新通道
    config &= ~(0xFF << 4);  // 清除CH1-CH8位
    config |= (channel_mask & 0xFF0);  // 只设置CH1-CH8位
    
    // 写回配置寄存器
    return ad799x_write_two_bytes(dev_addr, AD799X_CONFIG_REG, config);
}

// 启用/禁用滤波器
esp_err_t ad799x_set_filter(uint8_t dev_addr, bool enable) {
    uint16_t config;
    esp_err_t ret = ad799x_read_two_bytes(dev_addr, AD799X_CONFIG_REG, &config);
    if (ret != ESP_OK) {
        return ret;
    }
    
    if (enable) {
        config |= FLTR_BIT;
    } else {
        config &= ~FLTR_BIT;
    }
    
    return ad799x_write_two_bytes(dev_addr, AD799X_CONFIG_REG, config);
}

// 配置ALERT/BUSY引脚
esp_err_t ad799x_config_alert_pin(uint8_t dev_addr, bool alert_enable, bool busy_mode, bool active_high) {
    uint16_t config;
    esp_err_t ret = ad799x_read_two_bytes(dev_addr, AD799X_CONFIG_REG, &config);
    if (ret != ESP_OK) {
        return ret;
    }
    
    // 设置ALERT_EN位
    if (alert_enable) {
        config |= ALERT_EN_BIT;
    } else {
        config &= ~ALERT_EN_BIT;
    }
    
    // 设置BUSY/ALERT模式
    if (busy_mode) {
        config |= BUSY_ALERT_BIT;
    } else {
        config &= ~BUSY_ALERT_BIT;
    }
    
    // 设置极性
    if (active_high) {
        config |= ALERT_POLARITY_BIT;
    } else {
        config &= ~ALERT_POLARITY_BIT;
    }
    
    return ad799x_write_two_bytes(dev_addr, AD799X_CONFIG_REG, config);
}

// 模式1: 使用CONVST引脚触发转换
// 注意: 需要外部连接CONVST引脚到GPIO并配置为输出
esp_err_t ad799x_mode1_trigger_conversion(uint8_t dev_addr, gpio_num_t convst_pin) {
    // 确保配置寄存器中的命令位为0
    uint16_t config;
    esp_err_t ret = ad799x_read_two_bytes(dev_addr, AD799X_CONFIG_REG, &config);
    if (ret != ESP_OK) {
        return ret;
    }
    
    if ((config & 0xF000) != 0) {
        config &= ~0xF000;  // 清除命令位
        ret = ad799x_write_two_bytes(dev_addr, AD799X_CONFIG_REG, config);
        if (ret != ESP_OK) {
            return ret;
        }
    }
    
    // 触发CONVST引脚 (高电平至少1μs，然后低电平)
    gpio_set_level(convst_pin, 1);
    // ets_delay_us(2);  // 等待2μs确保满足最小时间要求
    esp_rom_delay_us(2);  // 等待2μs确保满足最小时间要求
    gpio_set_level(convst_pin, 0);
    
    return ESP_OK;
}

// 模式2: 命令模式触发转换
esp_err_t ad799x_mode2_trigger_conversion(uint8_t dev_addr, uint8_t channel_cmd) {
    // 通道命令应为0x8X (X=0-7) 或0x70表示序列模式
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (dev_addr << 1) | I2C_MASTER_WRITE, true);
    i2c_master_write_byte(cmd, channel_cmd, true);  // 包含命令位的地址指针
    i2c_master_stop(cmd);
    esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_PORT_NUM, cmd, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
    i2c_cmd_link_delete(cmd);
    return ret;
}

// 读取转换结果 (12位数据)
esp_err_t ad799x_read_conversion_result(uint8_t dev_addr, uint16_t *result, uint8_t *channel, bool *alert) {
    uint16_t data;
    esp_err_t ret = ad799x_read_two_bytes(dev_addr, AD799X_CONV_RES_REG, &data);
    if (ret != ESP_OK) {
        return ret;
    }
    
    // 解析数据
    *alert = (data >> 15) & 0x1;
    *channel = (data >> 12) & 0x7;
    *result = data & 0x0FFF;  // 12位数据
    
    return ESP_OK;
}

// 读取所有已启用通道的结果 (适用于序列模式)
esp_err_t ad799x_read_all_enabled_channels(uint8_t dev_addr, uint16_t results[8], bool *alert) {
    uint16_t config;
    esp_err_t ret = ad799x_read_two_bytes(dev_addr, AD799X_CONFIG_REG, &config);
    if (ret != ESP_OK) {
        return ret;
    }
    
    uint8_t enabled_channels = (config >> 4) & 0xFF;
    uint8_t channel_count = 0;
    
    // 计算启用的通道数
    for (int i = 0; i < 8; i++) {
        if (enabled_channels & (1 << i)) {
            channel_count++;
        }
    }
    
    if (channel_count == 0) {
        return ESP_ERR_INVALID_ARG;
    }
    
    // 读取所有通道数据
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (dev_addr << 1) | I2C_MASTER_WRITE, true);
    i2c_master_write_byte(cmd, AD799X_CONV_RES_REG, true);
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (dev_addr << 1) | I2C_MASTER_READ, true);
    
    // 读取所有通道数据 (每个通道2字节)
    for (int i = 0; i < channel_count; i++) {
        uint8_t msb, lsb;
        i2c_master_read_byte(cmd, &msb, (i == channel_count - 1) ? I2C_MASTER_NACK : I2C_MASTER_ACK);
        i2c_master_read_byte(cmd, &lsb, (i == channel_count - 1) ? I2C_MASTER_NACK : I2C_MASTER_ACK);
        
        uint16_t data = (msb << 8) | lsb;
        uint8_t ch = (data >> 12) & 0x7;
        results[ch] = data & 0x0FFF;
        
        if (i == 0) {
            *alert = (data >> 15) & 0x1;
        }
    }
    
    i2c_master_stop(cmd);
    ret = i2c_master_cmd_begin(I2C_MASTER_PORT_NUM, cmd, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
    i2c_cmd_link_delete(cmd);
    
    return ret;
}

// 设置限值寄存器 (用于ALERT功能)
esp_err_t ad799x_set_limit_registers(uint8_t dev_addr, uint8_t channel, uint16_t high_limit, uint16_t low_limit, uint16_t hysteresis) {
    if (channel < 1 || channel > 4) {
        return ESP_ERR_INVALID_ARG;  // 只有CH1-CH4有限值寄存器
    }
    
    // 计算寄存器地址 (参见手册表8)
    uint8_t high_reg = 0x04 + (channel - 1) * 3;
    uint8_t low_reg = high_reg + 1;
    uint8_t hyst_reg = high_reg + 2;
    
    esp_err_t ret;
    
    // 写入高限值
    ret = ad799x_write_two_bytes(dev_addr, high_reg, high_limit);
    if (ret != ESP_OK) return ret;
    
    // 写入低限值
    ret = ad799x_write_two_bytes(dev_addr, low_reg, low_limit);
    if (ret != ESP_OK) return ret;
    
    // 写入滞后值
    return ad799x_write_two_bytes(dev_addr, hyst_reg, hysteresis);
}

// 配置自动循环模式 (模式3)
esp_err_t ad799x_set_auto_cycle_mode(uint8_t dev_addr, uint8_t cycle_time) {
    // cycle_time: 0=禁用, 1-7对应不同的时间间隔 (参见手册表24)
    if (cycle_time > 7) {
        return ESP_ERR_INVALID_ARG;
    }
    
    // 设置循环定时器寄存器 (只使用最低3位)
    return ad799x_write_byte(dev_addr, AD799X_CYCLE_TIMER_REG, cycle_time & 0x07);
}

// 读取ALERT状态寄存器
esp_err_t ad799x_read_alert_status(uint8_t dev_addr, uint8_t *status) {
    return ad799x_read_byte(dev_addr, AD799X_ALERT_STATUS_REG, status);
}

// 清除ALERT状态
esp_err_t ad799x_clear_alert_status(uint8_t dev_addr) {
    // 方法1: 写入配置寄存器D2D1=11
    uint16_t config;
    esp_err_t ret = ad799x_read_two_bytes(dev_addr, AD799X_CONFIG_REG, &config);
    if (ret != ESP_OK) {
        return ret;
    }
    
    config |= (ALERT_EN_BIT | BUSY_ALERT_BIT);
    return ad799x_write_two_bytes(dev_addr, AD799X_CONFIG_REG, config);
    
    // 方法2: 也可以直接向ALERT状态寄存器写入0xFF
    // return ad799x_write_byte(dev_addr, AD799X_ALERT_STATUS_REG, 0xFF);
}

// void ad799x_example() {
//     // 初始化I2C
//     // ad799x_i2c_init();
    
//     // 初始化AD7998 (AS引脚接地)
//     uint8_t dev_addr = 0x22;
//     ad799x_init(dev_addr);
    
//     // 配置ALERT引脚
//     ad799x_config_alert_pin(dev_addr, true, false, false);  // 启用ALERT, 低电平有效
    
//     // 设置CH1和CH2的限值
//     ad799x_set_limit_registers(dev_addr, 1, 0x0C00, 0x0400, 0x0010);  // CH1高限0x0C00, 低限0x0400, 滞后0x0010
//     ad799x_set_limit_registers(dev_addr, 2, 0x0A00, 0x0600, 0x0010);
    
//     // 启用CH1和CH2
//     ad799x_set_channel(dev_addr, PosSenUpperChAll);
    
//     // 模式1: 使用CONVST引脚触发转换
//     // 假设CONVST连接到GPIO23
//     gpio_config_t io_conf = {
//         .pin_bit_mask = (1ULL << GPIO_NUM_23),
//         .mode = GPIO_MODE_OUTPUT,
//         .pull_up_en = GPIO_PULLUP_DISABLE,
//         .pull_down_en = GPIO_PULLDOWN_DISABLE,
//         .intr_type = GPIO_INTR_DISABLE,
//     };
//     gpio_config(&io_conf);
    
//     // 触发转换
//     // ad799x_mode1_trigger_conversion(dev_addr, GPIO_NUM_23);
    
//     // 读取结果
//     uint16_t result;
//     uint8_t channel;
//     bool alert;
//     ad799x_read_conversion_result(dev_addr, &result, &channel, &alert);
//     ESP_LOGI(TAG, "Channel %d: 0x%03X, Alert: %d", channel, result, alert);
    
//     // 模式2: 命令模式触发CH1转换
//     ad799x_mode2_trigger_conversion(dev_addr, 0x80);  // 0x80 = 转换CH1
    
//     // 读取结果
//     ad799x_read_conversion_result(dev_addr, &result, &channel, &alert);
//     ESP_LOGI(TAG, "Channel %d: 0x%03X, Alert: %d", channel, result, alert);
    
//     // 模式3: 自动循环模式 (每32个转换周期)
//     ad799x_set_auto_cycle_mode(dev_addr, 1);  // 1 = Tconvert×32
    
//     // 读取所有启用通道的结果
//     uint16_t results[8] = {0};
//     ad799x_read_all_enabled_channels(dev_addr, results, &alert);
//     for (int i = 0; i < 8; i++) {
//         if (results[i] != 0) {
//             ESP_LOGI(TAG, "Channel %d: 0x%03X", i+1, results[i]);
//         }
//     }
    
//     // 检查ALERT状态
//     uint8_t alert_status;
//     ad799x_read_alert_status(dev_addr, &alert_status);
//     if (alert_status) {
//         ESP_LOGW(TAG, "Alert detected! Status: 0x%02X", alert_status);
//         ad799x_clear_alert_status(dev_addr);
//     }
// }